﻿#include "basemap.h"
#include "baserole.h"
#include "common/common.h"
#include "mapmanager.h"

BaseMapTile::BaseMapTile(int index)
    : mIndex(index)
{

}

BaseMapTile::~BaseMapTile()
{

}

/**
 * @brief BaseMapTile::addRole 添加一个角色到可视角色列表中
 * @param role
 * @return
 */
bool BaseMapTile::addRole(BaseRole *role)
{
    if(role == NULL || isExistRole(role))
        return false;

    mRoleList.push_front(role);

    return true;
}

/**
 * @brief BaseMapTile::delRole 从可视角色列表中删除指定角色
 * @param role
 * @return
 */
bool BaseMapTile::delRole(BaseRole *role)
{
    if(role == NULL)
        return false;

    QList<BaseRole*>::iterator iter = qFind(mRoleList.begin(),
                                            mRoleList.end(),
                                            role);
    if(iter != mRoleList.end())
        mRoleList.erase(iter);

    //role->setMapIndex(-1);

    return true;
}

/**
 * @brief BaseMapTile::clearRoleList 清空可视角色列表
 */
void BaseMapTile::clearRoleList(void)
{
    mRoleList.clear();
}

/**
 * @brief BaseMapTile::isExistRole 检测指定角色是否存在列表中
 * @param role
 * @return
 */
bool BaseMapTile::isExistRole(BaseRole *role)
{
    if(role == NULL) return false;

    QList<BaseRole*>::iterator iter = qFind(mRoleList.begin(),
                                            mRoleList.end(),
                                            role);
    if(iter == mRoleList.end())
        return false;

    return true;
}

/**
 * @brief BaseMapTile::getRoleByRect 得到指定范围内的所有角色
 * @param rect
 * @return
 */
QList<BaseRole*> BaseMapTile::getRoleByRect(QRect rect)
{
    QList<BaseRole*> returnlist;

    QList<BaseRole*>::iterator iter = mRoleList.begin();
    for(;iter != mRoleList.end();iter++)
    {
        if(rect.contains((*iter)->getPosition()))
            returnlist.push_back((*iter));
    }

    return returnlist;
}

/**
 * @brief BaseMapTile::getTypeRoles 得到地图区域中相应所有角色
 * @param type
 * @return
 */
QList<BaseRole*> BaseMapTile::getTypeRoles(RoleType type)
{
    QList<BaseRole*> returnlist;

    QList<BaseRole*>::iterator iter = mRoleList.begin();
    for(;iter != mRoleList.end();iter++)
    {
        if((*iter)->getRoleType() == type)
            returnlist.push_back((*iter));
    }

    return returnlist;
}

//////////////////////////////////////////////////////////////////////////////////////////

BaseMap::BaseMap(int mapindex)
    : mMapIndex(mapindex),
      mMonsterMaxCount(0)
{

}

BaseMap::~BaseMap()
{
    delMapTiles();
}

/**
 * @brief BaseMap::delMapTiles 删除所有的地图块
 */
void BaseMap::delMapTiles(void)
{
    QHash<int,BaseMapTile*>::iterator iter = mMapTileList.begin();
    for(;iter != mMapTileList.end();iter++)
        delete iter.value();

    mMapTileList.clear();
}

/**
 * @brief BaseMap::setTileSize 设置地图块高宽
 * @param size
 */
void BaseMap::setTileSize(QSize size)
{
    if(!mRect.isValid() || !size.isValid())
        return;

    mTileSize = size;

    int tmpNorTileWidth = mRect.width() / size.width();
    int tmpLastTileWidth = (mRect.width() % size.width() > 0 ? tmpNorTileWidth+(mRect.width() % size.width()) : tmpNorTileWidth);
    int tmpNorTileHeight = mRect.height() / size.height();
    int tmpLastTileHeight = (mRect.height() % size.height() > 0 ? tmpNorTileHeight+(mRect.height() % size.height()) : tmpNorTileHeight);

    // 清除所有的地图块
    delMapTiles();

    for(int i=0;i<size.width()*size.height();i++)
    {
        BaseMapTile *pBaseMapTile = new BaseMapTile(i);

        int tmptilewidth = tmpNorTileWidth;
        int tmptileheight = tmpNorTileHeight;

        if(i % size.width()+1 == size.width())
            tmptilewidth = tmpLastTileWidth;

        if(i / size.width()+1 == size.height())
            tmptileheight = tmpLastTileHeight;

        pBaseMapTile->setRect(QRect(QPoint((i%size.width())*tmpNorTileWidth,(i/size.width())*tmpNorTileHeight),
                                    QSize(tmptilewidth,tmptileheight)));

        mMapTileList[i] = pBaseMapTile;
    }
}

/**
 * @brief BaseMap::getRoleMapTile 根据角色坐标找到相应地图块
 * @param role
 * @return
 */
int BaseMap::getRoleMapTile(BaseRole *role)
{
    if(role == NULL || mMapTileList.isEmpty())
        return -1;

    QHash<int,BaseMapTile*>::iterator iter = mMapTileList.begin();
    for(;iter != mMapTileList.end();iter++)
    {
        if(iter.value()->getRect().contains(role->getPosition()))
            return iter.key();
    }

    return -1;
}

/**
 * @brief BaseMap::getTypeRoles 得到地图区域中相应所有角色
 * @param type
 * @return
 */
QList<BaseRole*> BaseMap::getTypeRoles(RoleType type)
{
    QList<BaseRole*> returnlist;

    QHash<int,BaseMapTile*>::iterator iter = mMapTileList.begin();
    for(;iter != mMapTileList.end();iter++)
    {
        returnlist.append(iter.value()->getTypeRoles(type));
    }

    return returnlist;
}

/**
 * @brief BaseMap::isExistRole 检测当前地图是否存在这个角色
 * @param role
 * @return 如果存在返回角色所在地图块
 */
int BaseMap::isExistRole(BaseRole *role)
{
    if(role == NULL) return -1;

    QHash<int,BaseMapTile*>::iterator iter = mMapTileList.find(role->getCurMapTile());
    if(iter != mMapTileList.end())
    {
        if(iter.value()->isExistRole(role))
            return iter.key();
    }

    return -1;
}

/**
 * @brief BaseMap::updateRoleViewRoleList 更新角色可视角色列表
 * @param role
 */
void BaseMap::updateRoleViewRoleList(BaseRole *role)
{
    if(role == NULL) return;

    // 首先得到角色在地图中的可视范围
    QRect tmpViewRect = QRect(QPoint(role->getPosition().x()-role->getViewRect().size().width()/2,
                                     role->getPosition().y()-role->getViewRect().size().height()/2),
                              role->getViewRect().size());

    if(role->getRoleType() == ROLETYPE_MONSTER)
    {
        tmpViewRect = QRect(QPoint(role->getPosition().x()-role->getViewRect().size().width(),
                                   role->getPosition().y()-role->getViewRect().size().height()),
                            role->getViewRect().size()*2);
    }

    if(role->getRoleType() == ROLETYPE_PLAYER)
    {
        if(tmpViewRect.x() < 0)
        {
            tmpViewRect.setX(0);
            tmpViewRect.setWidth(role->getViewRect().size().width());
        }
        if(tmpViewRect.y() < 0)
        {
            tmpViewRect.setY(0);
            tmpViewRect.setHeight(role->getViewRect().size().height());
        }
    }

    // 设置角色在地图中的可视范围
    role->setMapViewRect(tmpViewRect);

    // 清除角色中不在视觉范围内的角色
    role->delRoleNoRect(tmpViewRect);

    QHash<int,BaseMapTile*>::iterator iter = mMapTileList.begin();
    for(;iter != mMapTileList.end();iter++)
    {
        if(iter.value()->getRect().intersects(tmpViewRect))
        {
            role->addRoles(iter.value()->getRoleByRect(tmpViewRect));
        }
    }

    if(role->isStateChanged())
    {
        role->setStateChanged(false);

        // 向当前角色可视范围内更新它的位置
        QList<BaseRole*> rolelist = role->getViewRoleList();
        QList<BaseRole*>::iterator iterrolelist = rolelist.begin();
        for(;iterrolelist != rolelist.end();iterrolelist++)
        {
            if((*iterrolelist)->getRoleType() != ROLETYPE_PLAYER)
                continue;

            // 怪物改变后，要更新怪物视觉范围内的玩家
            updateRoleViewRoleList((*iterrolelist));
        }
    }

    if(role->getRoleType() == ROLETYPE_PLAYER)
    {
        QJsonObject returnObj;
        returnObj["msgtype"] = IDD_NETWORK_ROLEPOSITION;

        QJsonArray roleArray;

        // 向当前角色可视范围内更新它的位置
        QList<BaseRole*> rolelist = role->getViewRoleList();
        QList<BaseRole*>::iterator iterrolelist = rolelist.begin();
        for(;iterrolelist != rolelist.end();iterrolelist++)
        {
            QJsonObject roleObj;
            roleObj["type"] = (*iterrolelist)->getRoleType();
            roleObj["state"] = (*iterrolelist)->getState();
            roleObj["id"] = (*iterrolelist)->getID();
            roleObj["name"] = (*iterrolelist)->getName();
            roleObj["posX"] = (*iterrolelist)->getPosition().x();
            roleObj["posY"] = (*iterrolelist)->getPosition().y();
            roleObj["angle"] = (*iterrolelist)->getAngle();
            roleObj["blood"] = (*iterrolelist)->getBlood();
            roleObj["experience"] = (*iterrolelist)->getExperience();
            roleObj["grade"] = (*iterrolelist)->getGrade();

            QJsonObject viewPortObj;
            viewPortObj["x"] = (*iterrolelist)->getMapViewRect().x();
            viewPortObj["y"] = (*iterrolelist)->getMapViewRect().y();
            viewPortObj["x1"] = (*iterrolelist)->getMapViewRect().bottomRight().x();
            viewPortObj["y1"] = (*iterrolelist)->getMapViewRect().bottomRight().y();

            roleObj["viewrect"] = viewPortObj;

            roleArray.push_back(roleObj);
        }

        returnObj["content"] = roleArray;

        MapManager::getSingleton().Send(role->getWebSocket(),
                                        JsonToString(returnObj));
    }
}

/**
 * @brief BaseMap::addRoleToMap 加入一个角色到地图中
 * @param role
 */
void BaseMap::addRoleToMap(BaseRole *role)
{
    QJsonObject tileObj;
    tileObj["row"] = this->getTileSize().width();
    tileObj["list"] = this->getTileSize().height();

    QJsonObject rectObj;
    rectObj["x"] = this->getRect().x();
    rectObj["y"] = this->getRect().y();
    rectObj["w"] = this->getRect().width();
    rectObj["h"] = this->getRect().height();

    QJsonObject mapObj;
    mapObj["id"] = this->getMapIndex();
    mapObj["name"] = this->getName();
    mapObj["maxmonster"] = this->getMaxMonsterCount();
    mapObj["tileSize"] = tileObj;
    mapObj["rect"] = rectObj;

    QJsonArray entrancearr;

    QVector<tagMapEntrance> mapentrances = this->getMapEntrances();
    for(int i=0;i<mapentrances.size();i++)
    {
        QJsonObject temprectObj;
        temprectObj["x"] = mapentrances[i].rect.x();
        temprectObj["y"] = mapentrances[i].rect.y();
        temprectObj["w"] = mapentrances[i].rect.width();
        temprectObj["h"] = mapentrances[i].rect.height();

        QJsonObject entranceinfoObj;
        entranceinfoObj["rect"] = temprectObj;
        entranceinfoObj["targetmap"] = mapentrances[i].targetmap;
        entranceinfoObj["remark"] = mapentrances[i].remark;

        entrancearr.push_back(entranceinfoObj);
    }

    mapObj["mapentrance"] = entrancearr;

    QJsonObject returnObj;
    returnObj["msgtype"] = IDD_NETWORK_ENTERMAP;
    returnObj["map"] = mapObj;

    MapManager::getSingleton().Send(role->getWebSocket(),JsonToString(returnObj));

    this->updateRoleMapTile(role);
}

/**
 * @brief BaseMap::updateRoleMapTile 根据角色坐标更新相应地图块
 * @param role
 */
void BaseMap::updateRoleMapTile(BaseRole *role)
{
    if(role == NULL) return;

    // 首先检测角色是否在地图中
    int tileIndex = isExistRole(role);
    if(tileIndex > -1)
    {
        // 如果角色不在原区域，原区域清除这个角色，新区域添加这个角色
        if(!mMapTileList[tileIndex]->getRect().contains(role->getPosition()))
        {
            // 原区域删除
            mMapTileList[tileIndex]->delRole(role);

            // 新区域加入
            int newTileIndex = getRoleMapTile(role);
            if(newTileIndex > -1) mMapTileList[newTileIndex]->addRole(role);

            //role->setMapIndex(this->getMapIndex());
            role->setLastMapTile(tileIndex);
            role->setCurMapTile(newTileIndex);
        }
    }
    else
    {
        // 新区域加入
        int newTileIndex = getRoleMapTile(role);
        if(newTileIndex > -1) mMapTileList[newTileIndex]->addRole(role);

        //role->setMapIndex(this->getMapIndex());
        role->setLastMapTile(-1);
        role->setCurMapTile(newTileIndex);
    }

    // 更新角色的视觉角色列表
    updateRoleViewRoleList(role);
}

/**
 * @brief BaseMap::getMapEntrance 根据一个坐标点得到相应地图入口信息
 * @param position
 * @return
 */
tagMapEntrance* BaseMap::getMapEntrance(QPoint position)
{
    for(int i=0;i<mMapEntrance.size();i++)
    {
        if(mMapEntrance[i].rect.contains(position))
            return &mMapEntrance[i];
    }

    return NULL;
}

/**
 * @brief BaseMap::generatearandombirthcoordinate 得到一个随机出生点
 * @return
 */
QPoint BaseMap::generatearandombirthcoordinate(void)
{
    QPoint decPoint;

    for(int i=0;i<10;i++)
    {
         decPoint = QPoint(qrand()%this->getRect().width(),
                           qrand()%this->getRect().height());

         if(getMapEntrance(decPoint) == NULL)
             return decPoint;
    }

    return this->getPlayerStartPos();
}

/**
 * @brief BaseMap::delRoleFromMap 从地图中清除指定的角色
 * @param role
 */
void BaseMap::delRoleFromMap(BaseRole *role)
{
    if(role == NULL || role->getCurMapTile() < 0)
        return;

    mMapTileList[role->getCurMapTile()]->delRole(role);

    print_log(LOG_INFO,
              QString::fromLocal8Bit("玩家离开:")+
                       role->getName()+
                       QString::asprintf(" ID:%d",role->getID())+
                       QString::fromLocal8Bit(" 坐标:")+
                       QString::asprintf("%d,%d",role->getPosition().x(),role->getPosition().y())+
                       QString::fromLocal8Bit(" 角度:")+
                       QString::asprintf("%f",role->getAngle()),
              "1|0|1");
}
